#include "inttypes.h"
#include "common.h"
#include <stdio.h>
#include <stdlib.h>

#include "extint.h"
#include "saa6588.h"
#include "io.h"
#include <i2c.h>
#include "i2c.h"

rds_t Rds;

#define SAA6588_READ  0x21
#define SAA6588_WRITE 0x20

void saa6588_init(void)
{
  StartI2C2();
  /* Wait till Start sequence is completed */
  while(I2C2CONbits.SEN);
  /* Clear interrupt flag */
  IFS0bits.IC2IF = 0;
  /* Write Slave address and set master for transmission */
  MasterWriteI2C2( SAA6588_WRITE );
  /* Wait till address is transmitted */
  while( I2C2STATbits.TBF );  // 8 clock cycles
  while(!IFS3bits.MI2C2IF);   // Wait for 9th clock cycle
  IFS3bits.MI2C2IF = 0;       // Clear interrupt flag
  while( I2C2STATbits.ACKSTAT );
  /* Transmit string of data */
  MasterWriteI2C2( 232 );
  MasterWriteI2C2( 32 );
  MasterWriteI2C2( 47 );
  StopI2C2();
  /* Wait till stop sequence is completed */
  while( I2C2CONbits.PEN );
  IdleI2C2();
}

void rds_Init(void)
{
  Rds.blockready = 0;
  Rds.counter = 0;
  Rds.retdata = 0;

  saa6588_init();

  pCN0Function = rds_int;
}

unsigned int rds_Calculate_Syndrom(unsigned long Data)
{
  u16 MSB16, LSB16;

  MSB16 = (Data>>16) & 0x03FF;
  LSB16 = Data;

  MSB16 &= 0x3FFF;			    // nur 26 Bit verwenden
  if((LSB16 & 0x0001) == 0x0001)            // Multiplikation des empfangen Wortes mit
	MSB16 ^= 0x031B;		    // der Kontrollmatrix
  if((LSB16 & 0x0002) == 0x0002)
	MSB16 ^= 0x038F;
  if((LSB16 & 0x0004) == 0x0004)
	MSB16 ^= 0x02A7;
  if((LSB16 & 0x0008) == 0x0008)
	MSB16 ^= 0x00F7;
  if((LSB16 & 0x0010) == 0x0010)
	MSB16 ^= 0x01EE;
  if((LSB16 & 0x0020) == 0x0020)
	MSB16 ^= 0x03DC;
  if((LSB16 & 0x0040) == 0x0040)
	MSB16 ^= 0x0201;
  if((LSB16 & 0x0080) == 0x0080)
	MSB16 ^= 0x01BB;
  if((LSB16 & 0x0100) == 0x0100)
	MSB16 ^= 0x0376;
  if((LSB16 & 0x0200) == 0x0200)
	MSB16 ^= 0x0355;
  if((LSB16 & 0x0400) == 0x0400)
	MSB16 ^= 0x0313;
  if((LSB16 & 0x0800) == 0x0800)
	MSB16 ^= 0x039F;
  if((LSB16 & 0x1000) == 0x1000)
	MSB16 ^= 0x0287;
  if((LSB16 & 0x2000) == 0x2000)
	MSB16 ^= 0x00B7;
  if((LSB16 & 0x4000) == 0x4000)
	MSB16 ^= 0x016E;
  if((LSB16 & 0x8000) == 0x8000)
	MSB16 ^= 0x02DC;
  return MSB16;
}

void rds_Decode_Group(void)
{
  int Typecode, Adresscode;
  Rds.iBlock2 = (Rds.lBlock2 & 0x03FFFC00)>>10;
  Rds.iBlock3 = (Rds.lBlock3 & 0x03FFFC00)>>10;
  Rds.iBlock4 = (Rds.lBlock4 & 0x03FFFC00)>>10;

  Rds.rdsPI   = (Rds.lBlock1 & 0x03FFFC00)>>10;	// PI-Code

  Rds.rdsPTY  = (Rds.iBlock2 & 0x3E0)>>5;	// PTY-Code

// Gruppeneinteilung

  switch(Rds.rdsPTY)				// PTY-Namen
  {
    case 0: {strcpy((char*)Rds.rdsPTY_NAME,"None            ");break;}
    case 1: {strcpy((char*)Rds.rdsPTY_NAME,"News            ");break;}
    case 2: {strcpy((char*)Rds.rdsPTY_NAME,"Current Affairs ");break;}
    case 3: {strcpy((char*)Rds.rdsPTY_NAME,"Information     ");break;}
    case 4: {strcpy((char*)Rds.rdsPTY_NAME,"Sport           ");break;}
    case 5: {strcpy((char*)Rds.rdsPTY_NAME,"Education       ");break;}
    case 6: {strcpy((char*)Rds.rdsPTY_NAME,"Drama           ");break;}
    case 7: {strcpy((char*)Rds.rdsPTY_NAME,"Culture         ");break;}
    case 8: {strcpy((char*)Rds.rdsPTY_NAME,"Science         ");break;}
    case 9: {strcpy((char*)Rds.rdsPTY_NAME,"Varied Speech   ");break;}
    case 10:{strcpy((char*)Rds.rdsPTY_NAME,"Pop Music       ");break;}
    case 11:{strcpy((char*)Rds.rdsPTY_NAME,"Rock Music      ");break;}
    case 12:{strcpy((char*)Rds.rdsPTY_NAME,"Easy Listening  ");break;}
    case 13:{strcpy((char*)Rds.rdsPTY_NAME,"Light Classic M ");break;}
    case 14:{strcpy((char*)Rds.rdsPTY_NAME,"Serious Classic ");break;}
    case 15:{strcpy((char*)Rds.rdsPTY_NAME,"Other Music     ");break;}
    case 16:{strcpy((char*)Rds.rdsPTY_NAME,"Wheather        ");break;}
    case 17:{strcpy((char*)Rds.rdsPTY_NAME,"Finance         ");break;}
    case 18:{strcpy((char*)Rds.rdsPTY_NAME,"Children´s Progs");break;}
    case 19:{strcpy((char*)Rds.rdsPTY_NAME,"Social Affairs  ");break;}
    case 20:{strcpy((char*)Rds.rdsPTY_NAME,"Religion        ");break;}
    case 21:{strcpy((char*)Rds.rdsPTY_NAME,"Phone In        ");break;}
    case 22:{strcpy((char*)Rds.rdsPTY_NAME,"Travel and Tour ");break;}
    case 23:{strcpy((char*)Rds.rdsPTY_NAME,"Leisure & Hobby ");break;}
    case 24:{strcpy((char*)Rds.rdsPTY_NAME,"Jazz Music      ");break;}
    case 25:{strcpy((char*)Rds.rdsPTY_NAME,"Country Music   ");break;}
    case 26:{strcpy((char*)Rds.rdsPTY_NAME,"National Music  ");break;}
    case 27:{strcpy((char*)Rds.rdsPTY_NAME,"Oldies Music    ");break;}
    case 28:{strcpy((char*)Rds.rdsPTY_NAME,"Folk Music      ");break;}
    case 29:{strcpy((char*)Rds.rdsPTY_NAME,"Documentary     ");break;}
    case 30:{strcpy((char*)Rds.rdsPTY_NAME,"Alarm Test      ");break;}
    case 31:{strcpy((char*)Rds.rdsPTY_NAME,"ALERT! ALERT!   ");break;}
  }
  Typecode = (Rds.iBlock2 & 0xF800);
  switch(Typecode)
  {
    case _0A:	// Sendername
    {
      if((Rds.iBlock2 & 0x0003) == 0x0000)		// 1. und 2. BS
      {
	Rds.rdsNAME[0] = Rds.iBlock4>>8;
	Rds.rdsNAME[1] = Rds.iBlock4;
      }
      if((Rds.iBlock2 & 0x0003) == 0x0001)		// 3. und 4. BS
      {
	Rds.rdsNAME[2] = Rds.iBlock4>>8;
	Rds.rdsNAME[3] = Rds.iBlock4;
      }
      if((Rds.iBlock2 & 0x0003) == 0x0002)		// 5. und 6. BS
      {
	Rds.rdsNAME[4] = Rds.iBlock4>>8;
	Rds.rdsNAME[5] = Rds.iBlock4;
      }
      if((Rds.iBlock2 & 0x0003) == 0x0003)		// 7. und 8. BS
      {
	Rds.rdsNAME[6] = Rds.iBlock4>>8;
	Rds.rdsNAME[7] = Rds.iBlock4;
      }
      Rds.rdsNAME[8] = '\0';			// Terminierung
      break;
    }
    case _0B:
    {
      break;
    }
    case _1A:
    {
      break;
    }
    case _1B:
    {
      break;
    }
    case _2A:					// Radiotext
    {
      Adresscode = (Rds.iBlock2 & 0x000F);
      switch(Adresscode)
      {
	case 0:
	{
	  Rds.rdsTEXT[0] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[1] = Rds.iBlock3;
	  Rds.rdsTEXT[2] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[3] = Rds.iBlock4;
	  break;
	}
	case 1:
	{
	  Rds.rdsTEXT[4] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[5] = Rds.iBlock3;
	  Rds.rdsTEXT[6] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[7] = Rds.iBlock4;
	  break;
	}
	case 2:
	{
	  Rds.rdsTEXT[8] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[9] = Rds.iBlock3;
	  Rds.rdsTEXT[10] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[11] = Rds.iBlock4;
	  break;
	}
	case 3:
	{
	  Rds.rdsTEXT[12] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[13] = Rds.iBlock3;
	  Rds.rdsTEXT[14] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[15] = Rds.iBlock4;
	  break;
	}
	case 4:
	{
	  Rds.rdsTEXT[16] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[17] = Rds.iBlock3;
	  Rds.rdsTEXT[18] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[19] = Rds.iBlock4;
	  break;
	}
	case 5:
	{
	  Rds.rdsTEXT[20] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[21] = Rds.iBlock3;
	  Rds.rdsTEXT[22] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[23] = Rds.iBlock4;
	  break;
	}
	case 6:
	{
	  Rds.rdsTEXT[24] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[25] = Rds.iBlock3;
	  Rds.rdsTEXT[26] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[27] = Rds.iBlock4;
	  break;
	}
	case 7:
	{
	  Rds.rdsTEXT[28] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[29] = Rds.iBlock3;
	  Rds.rdsTEXT[30] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[31] = Rds.iBlock4;
	  break;
	}
	case 8:
	{
	  Rds.rdsTEXT[32] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[33] = Rds.iBlock3;
	  Rds.rdsTEXT[34] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[35] = Rds.iBlock4;
	  break;
	}
	case 9:
	{
	  Rds.rdsTEXT[36] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[37] = Rds.iBlock3;
	  Rds.rdsTEXT[38] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[39] = Rds.iBlock4;
	  break;
	}
	case 10:
	{
	  Rds.rdsTEXT[40] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[41] = Rds.iBlock3;
	  Rds.rdsTEXT[42] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[43] = Rds.iBlock4;
	  break;
	}
	case 11:
	{
	  Rds.rdsTEXT[44] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[45] = Rds.iBlock3;
	  Rds.rdsTEXT[46] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[47] = Rds.iBlock4;
	  break;
	}
	case 12:
	{
	  Rds.rdsTEXT[48] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[49] = Rds.iBlock3;
	  Rds.rdsTEXT[50] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[51] = Rds.iBlock4;
	  break;
	}
	case 13:
	{
	  Rds.rdsTEXT[52] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[53] = Rds.iBlock3;
	  Rds.rdsTEXT[54] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[55] = Rds.iBlock4;
	  break;
	}
	case 14:
	{
	  Rds.rdsTEXT[56] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[57] = Rds.iBlock3;
	  Rds.rdsTEXT[58] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[59] = Rds.iBlock4;
	  break;
	}
	case 15:
	{
	  Rds.rdsTEXT[60] = Rds.iBlock3>>8;
	  Rds.rdsTEXT[61] = Rds.iBlock3;
          Rds.rdsTEXT[62] = Rds.iBlock4>>8;
	  Rds.rdsTEXT[63] = Rds.iBlock4;
	  break;
	}
      }
      Rds.rdsTEXT[64] = '\0';	// Terminierung
      break;
    }
    case _2B:
    {
      break;
    }
    case _3A:
    {
      break;
    }
    case _3B:
    {
      break;
    }
    case _4A:		// Zeit/Datum
    {
      int Offset;
      Offset = (Rds.iBlock4 & 0x001F);
      Rds.hour_utc =  ((Rds.iBlock4 & 0xF000)>>12)|((Rds.iBlock3 & 0x0001)<<4);
      if((Rds.iBlock4 & 0x0020) == 0)
        Rds.hour_local = Rds.hour_utc + Offset/2;
      else
	Rds.hour_local = Rds.hour_utc - Offset/2;
      Rds.minute = ((Rds.iBlock4 & 0x0FC0)>>6);
      break;
    }
    case _4B:
    {
      break;
    }
    case _5A:
    {
      break;
    }
    case _5B:
    {
      break;
    }
    case _6A:
    {
      break;
    }
    case _6B:
    {
      break;
    }
    case _7A:
    {
      break;
    }
    case _7B:
    {
      break;
    }
    case _8A:
    {
      break;
    }
    case _8B:
    {
      break;
    }
    case _9A:
    {
      break;
    }
    case _9B:
    {
      break;
    }
    case _10A:
    {
      break;
    }
    case _10B:
    {
      break;
    }
    case _11A:
    {
      break;
    }
    case _11B:
    {
      break;
    }
    case _12A:
    {
      break;
    }
    case _12B:
    {
      break;
    }
    case _13A:
    {
      break;
    }
    case _13B:
    {
      break;
    }
    case _14A:
    {
      break;
    }
    case _14B:
    {
      break;
    }
    case _15A:
    {
      break;
    }
    case _15B:
    {
      break;
    }
    default:
    {
      break;
    }
  }
  // Sendername
}

void rds_int(void)
{
  //TODO:Rds.in = RDS_DATA_IN_bb;
  Rds.retdata = (Rds.retdata<<1) + Rds.in ;		// und schieben
  Rds.counter++;
  if(Rds.counter >= 26)
  {
    Rds.blockready = 1;
  }
}

unsigned int rds_Read_Group(void)
{
  if(Rds.blockready == 1)
  {
    Rds.blockready = 0;
    Rds.retblock = rds_Calculate_Syndrom(Rds.retdata); // Syndrom berechnen
    if (Rds.retblock == BLOCKA)
    {
      Rds.lBlock1 = Rds.retdata & 0x03FFFFFF;
      Rds.iBlock1 = Rds.retblock;
      Rds.counter = 0;
      Rds.retdata = 0;
      Rds.FBlock1 = 1;
    }
    else if (Rds.retblock == BLOCKB)
    {
      Rds.lBlock2 = Rds.retdata & 0x03FFFFFF;
      Rds.iBlock2 = Rds.retblock;
      Rds.counter = 0;
      Rds.retdata = 0;
      Rds.FBlock2 = 1;
    }
    else if ((Rds.retblock == BLOCKC)|(Rds.retblock == BLOCKC_))
    {
      Rds.lBlock3 = Rds.retdata & 0x03FFFFFF;
      Rds.iBlock3 = Rds.retblock;
      Rds.counter = 0;
      Rds.retdata = 0;
      Rds.FBlock3 = 1;
    }
    else if (Rds.retblock == BLOCKD)
    {
      Rds.lBlock4 = Rds.retdata & 0x03FFFFFF;
      Rds.iBlock4 = Rds.retblock;
      Rds.counter = 0;
      Rds.retdata = 0;
      Rds.FBlock4 = 1;
    }
    else
    {
      Rds.counter = 25;
    }
    if(Rds.FBlock1 & Rds.FBlock2 & Rds.FBlock3 & Rds.FBlock4)
    {
      Rds.FBlock1 = 0;
      Rds.FBlock2 = 0;
      Rds.FBlock3 = 0;
      Rds.FBlock4 = 0;
      return 1;
    }
  }
  return 0;
}
